/*
               #########                       
              ############                     
              #############                    
             ##  ###########                   
            ###  ###### #####                  
            ### #######   ####                 
           ###  ########## ####                
          ####  ########### ####               
         ####   ###########  #####             
        #####   ### ########   #####           
       #####   ###   ########   ######         
      ######   ###  ###########   ######       
     ######   #### ##############  ######      
    #######  #####################  ######     
    #######  ######################  ######    
   #######  ###### #################  ######   
   #######  ###### ###### #########   ######   
   #######    ##  ######   ######     ######   
   #######        ######    #####     #####    
    ######        #####     #####     ####     
     #####        ####      #####     ###      
      #####       ###        ###      #        
        ###       ###        ###               
         ##       ###        ###               
__________#_______####_______####______________

                我们的未来没有BUG              
* ==============================================================================
* Filename: TestProtoBuf
* Created:  2017/12/17 21:05:01
* Author:   HaYaShi ToShiTaKa
* Purpose:  
* ==============================================================================
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;

#region class
public class ProBufAPIFiled {
    public readonly string type;
    public readonly string name;
    private readonly static HashSet<string> m_numStrHash = new HashSet<string>{ 
        "double", 
        "float",
        "int32",
        "uin32",
        "int64",
        "uint64",
        "sint32",
        "sing64",
        "fixed32",
        "fixed64",
        "sfixed32",
        "sfixed64",
    };
    public ProBufAPIFiled(string lineStr) {
        name = lineStr;

        List<string> strList = SplitLine(lineStr);
        if (strList.Count != 3) {
            Debug.LogError("格式错误");
            Debug.Log(lineStr);
            return;
        }
        bool isArray = strList[0].Trim() == "repeated";
        string firstType = strList[1].Trim();
        name = strList[2];
        if (firstType == "string") {
            type = "string";
        }
        else if (firstType == "bool") {
            type = "boolen";
        }
        else if (m_numStrHash.Contains(firstType)) {
            type = "number";
        }
        else {
            type = firstType;
        }

        if (isArray) {
            type += "[]";
        }
    }
    
    private static List<string> SplitLine(string lineStr) {
        lineStr = lineStr.Trim();
        List<string> result = new List<string>();

        int lastIndex = 0;
        for (int i = 0, imax = lineStr.Length; i < imax; i++) {
            char c = lineStr[i];
            if (c == ' ') {
                string str = lineStr.Substring(lastIndex, i - lastIndex + 1);
                if (lastIndex != i) {
                    result.Add(str);
                }
                lastIndex = i + 1;
            }
            else if (i == imax - 1) {
                string str = lineStr.Substring(lastIndex, i - lastIndex + 1);
                result.Add(str);
            }
        }

        return result;
    }
    public override string ToString() {
        return string.Format("---@field public {0} {1}", name, type);
    }
}
public class ProBufAPI {
    public readonly string className;
    public readonly List<ProBufAPIFiled> fieldList = new List<ProBufAPIFiled>();

    public ProBufAPI(string messageStr, string parent) {
        //去注释
        string value = Regex.Replace(messageStr, "//.+", "");
        //替换制表符
        value = value.Replace("\t", " ");
        //去空白行
        value = Regex.Replace(value, @"\n[\s| ]*\r", "");

        className = Regex.Match(value, @"message([\s\S]*?)\{").Value.Replace("message", "");
        className = className.Replace("{", "");
        className = className.Trim();
        if (!string.IsNullOrEmpty(parent)) {
            className = parent + "." + className;
        }
        string fields = Regex.Replace(value, @"message([\s\S]*?)\{", "");
        fields = Regex.Replace(fields, @"([\s\S])\}", "").Trim();
        string[] fieldArray = fields.Split(';');
        for (int i = 0; i < fieldArray.Length - 1; i++) {
            string lineStr = (fieldArray[i].Split('=')[0]).Trim();
            if (string.IsNullOrEmpty(lineStr)) {
                continue;
            }
            ProBufAPIFiled pf = new ProBufAPIFiled(lineStr);
            fieldList.Add(pf);
        }
    }

    public override string ToString() {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(string.Format("---@class {0}", className));
        foreach (var item in fieldList) {
            sb.AppendLine(item.ToString());
        }
        return sb.ToString();
    }
}
#endregion

public class EmmyProtoBufExport {
    public static void ExportApi(string inPath, string outPath) {
        if (File.Exists(outPath)) {
            File.Delete(outPath);
        }

        string proBufStr = File.ReadAllText(inPath, Encoding.UTF8);
        EmmyProtoBufExport export = new EmmyProtoBufExport(proBufStr);
        FileStream fs = new FileStream(outPath, FileMode.Create);
        var utf8WithoutBom = new System.Text.UTF8Encoding(false);
        StreamWriter sw = new StreamWriter(fs, utf8WithoutBom);
        sw.Write(export.ToString());

        //清空缓冲区
        sw.Flush();
        sw.Close();
        fs.Close();
    }
    public override string ToString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0, imax = strList.Count; i < imax; i++) {
            sb.AppendLine(strList[i].ToString());
        }
        return sb.ToString();
    }

    #region private
    private readonly List<ProBufAPI> strList = new List<ProBufAPI>();
    private EmmyProtoBufExport(string pbStr) {
        pbStr = TrimUseless(pbStr);
        pbStr = Regex.Match(pbStr, @"message([\s\S])*\}").Value;
        strList.Clear();
        SplitMessage(pbStr, ref strList, "");
    }
    private static string TrimUseless(string value) {
        //去注释
        value = Regex.Replace(value, "//.+", "");
        //替换制表符
        value = value.Replace("\t", " ");
        //去空白行
        value = Regex.Replace(value, @"\n[\s| ]*\r", "");
        return value;
    }

    private static void SplitMessage(string pbStr, ref List<ProBufAPI> result, string parent) {
        int leftTime = 0;
        int rightTime = 0;
        int lastIndex = 0;
        for (int i = 0, imax = pbStr.Length; i < imax; i++) {
            char c = pbStr[i];
            if (c == '{') {
                leftTime++;
            }
            if (c == '}') {
                rightTime++;
            }
            if (leftTime == 0) continue;
            if (rightTime == 0) continue;
            if (leftTime == rightTime) {
                string msgStr = pbStr.Substring(lastIndex, i - lastIndex + 1);
                if (leftTime > 1) {
                    string p;
                    string selfContent = null;
                    msgStr = TrimMessage(msgStr, out p, out selfContent);
                    if (!string.IsNullOrEmpty(parent)) {
                        p = parent + "." + p;
                    }
                    SplitMessage(msgStr, ref result, p);
                    if (!string.IsNullOrEmpty(selfContent)) {
                        result.Add(new ProBufAPI(selfContent, parent));
                    }
                }
                else {
                    ProBufAPI api = new ProBufAPI(msgStr, parent);
                    result.Add(api);
                }
                lastIndex = i + 1;
                leftTime = 0;
                rightTime = 0;
            }
        }
    }
    private static string TrimMessage(string pbStr, out string parent, out string selfContent) {
        string result = "";
        parent = "";
        selfContent = null;
        string[] strList = pbStr.Split("{".ToCharArray(), 2);
        if (strList.Length == 2) {
            result = strList[1].TrimEnd('}').Trim();
            parent = (strList[0].Replace("message", "")).Trim();
        }
        else {
            result = pbStr;
        }
        string trimResult = Regex.Match(result, @"message([\s\S]*)\}").Value;
        if (trimResult != result) {
            selfContent = pbStr.Replace(trimResult, "");
            result = trimResult;
        }

        return result;
    }
    #endregion
}